﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using System.Collections.Generic;

namespace exsportance.Silverlight.Common.Controls
{
    /// <summary>
    /// From Laith Alasad (Laith.Alasad@hyro.com) 
    /// </summary>
    public class WheelMouseListener
    {
        private Stack<IMouseWheelObserver> _ElementStack;

        private WheelMouseListener()
        {
            this._ElementStack = new Stack<IMouseWheelObserver>();
            HtmlPage.Window.AttachEvent("DOMMouseScroll", OnMouseWheel);
            HtmlPage.Window.AttachEvent("onmousewheel", OnMouseWheel);
            HtmlPage.Document.AttachEvent("onmousewheel", OnMouseWheel);
            Application.Current.Exit += new EventHandler(OnApplicationExit);
        }

        /// <summary>   
        /// Detaches from the browser-generated scroll events. 
        ///  </summary> 
        private void Dispose()
        {
            HtmlPage.Window.DetachEvent("DOMMouseScroll", OnMouseWheel);
            HtmlPage.Window.DetachEvent("onmousewheel", OnMouseWheel);
            HtmlPage.Document.DetachEvent("onmousewheel", OnMouseWheel);
        }

        public void AddObserver(IMouseWheelObserver element)
        {
            element.MouseEnter += new MouseEventHandler(OnElementMouseEnter);
            element.MouseLeave += new MouseEventHandler(OnElementMouseLeave);
        }

        private void OnMouseWheel(object sender, HtmlEventArgs args)
        {
            double delta = 0;
            ScriptObject e = args.EventObject;
            if (e.GetProperty("detail") != null)
            {
                // Mozilla and Safari  
                delta = ((double)e.GetProperty("detail"));
            }
            else if (e.GetProperty("wheelDelta") != null)
            {
                // IE and Opera   
                delta = ((double)e.GetProperty("wheelDelta"));
            }

            delta = Math.Sign(delta);
            if (this._ElementStack.Count > 0)
                this._ElementStack.Peek().OnMouseWheel(new MouseWheelArgs(delta, args.ShiftKey, args.CtrlKey, args.AltKey));
        }

        private void OnElementMouseLeave(object sender, MouseEventArgs e)
        {
            this._ElementStack.Pop();
        }

        private void OnElementMouseEnter(object sender, MouseEventArgs e)
        {
            this._ElementStack.Push((IMouseWheelObserver)sender);
        }

        private void OnApplicationExit(object sender, EventArgs e)
        {
            this.Dispose();
        }

        private static WheelMouseListener _Instance = null;

        public static WheelMouseListener Instance
        {
            get
            {
                if (_Instance == null)
                {
                    _Instance = new WheelMouseListener();
                }
                return _Instance;
            }
        }
    }
}
